package me.yuxiaoyao.util.treeify;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;

/**
 * @author kerryzhang on 2020/10/19
 */

public class ReflectUtil {
    private ReflectUtil() {
    }

    public static <T> T newInstance(Class<T> cls, Object... params) throws NoSuchMethodException {
        if (cls.isInterface()) {
            throw new IllegalArgumentException("class can not be a interface");
        } else if (Modifier.isAbstract(cls.getModifiers())) {
            throw new IllegalArgumentException("class can not be a abstract class");
        }
        if (params.length > 0) {
            Class<?>[] classTypes = getClassTypes(params);
            try {
                Constructor<T> constructor = cls.getConstructor(classTypes);
                if (!Modifier.isPublic(constructor.getModifiers())) {
                    constructor.setAccessible(true);
                }
                return constructor.newInstance(params);
            } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ignored) {

            }
        }
        try {
            return cls.newInstance();
        } catch (InstantiationException | IllegalAccessException ignored) {
        }
        throw new NoSuchMethodException("not empty constructor on class = " + cls.getCanonicalName());
    }

    public static Class<?>[] getClassTypes(Object... object) {
        Class<?>[] res = new Class<?>[object.length];
        for (int i = 0; i < object.length; i++) {
            res[i] = getClassType(object[i]);
        }
        return res;
    }


    public static Class<?> getClassType(Object object) {
        return object.getClass();
    }

    public static Object[] getDefaultValues(Class<?>[] clss) {
        Object[] vals = new Object[clss.length];
        for (int i = 0; i < clss.length; i++) {
            vals[i] = getDefaultValue(clss[i]);
        }
        return vals;
    }

    public static Object getDefaultValue(Class<?> cls) {

        if (cls.isPrimitive()) {
            if (cls == int.class) {
                return 0;
            } else if (cls == boolean.class) {
                return false;
            } else if (cls == short.class) {
                return 0;
            } else if (cls == long.class) {
                return 0L;
            } else if (cls == byte.class) {
                return 0;
            } else if (cls == float.class) {
                return 0.0F;
            } else if (cls == double.class) {
                return 0.0;
            }
        }
        return null;

    }

}
